package internal

import (
	"crypto/md5"
	"fmt"
	"gameserver/server"
	"io"
	"strconv"
	"time"

	"gitee.com/night-tc/gobige/global"
	"gitee.com/night-tc/gobige/logger"
	"github.com/dgrijalva/jwt-go"
)

var LoginSalt = "cac3c74dcc7dbcab221eaf75f0ba7b40" //服务器启动后会修改,用于区分不同环境的
var Jwkey = []byte(LoginSalt)

const (
	Gin_Get_LoginModel = "LoginModel" // 放在Get中的 JWT 数据
	Gin_Get_UserID     = "UserID"     // 放在Get中的 UserID 数据
)

// CreateSig 根据uid和时间戳生成一个签名
func CreateSig(uid uint64, ts int64, channel string, isadult bool) (accessToken string) {
	h := md5.New()
	str := fmt.Sprintf("%d|%d|%s|%s|%t", uid, ts, channel, LoginSalt, isadult)
	h.Write([]byte(str))
	defer func() {
		logger.Debugf(server.LogKey_LoginFlow, "Create AccessToken=%v SourceStr=%v", accessToken, str)
	}()
	return fmt.Sprintf("%x", h.Sum(nil))
}

// CheckSig 校验客户端发送的信息
func CheckSig(token, uid, ts, channel string, isadult bool) bool {
	h := md5.New()
	str := fmt.Sprintf("%s|%s|%s|%s|%t", uid, ts, channel, LoginSalt, isadult)
	// logger.Debug(server.LogKey_LoginFlow, "Check AccessToken SourceStr: ", str)
	h.Write([]byte(str))
	s_token := fmt.Sprintf("%x", h.Sum(nil))
	if s_token != token {
		logger.Warnf("CheckSig fail,SourceStr:%s s_token %s c_token %s", str, s_token, token)
		return false
	}
	// logger.Debug(server.LogKey_LoginFlow, "CheckSigWW c_token ", token)
	return true
}

// 生成Token
func CreateToken(pid uint64) (string, int64) {
	curtime := time.Now().Add(global.Expire1Day).Unix()
	h := md5.New()

	_, _ = io.WriteString(h, strconv.FormatInt(curtime, 10))
	_, _ = io.WriteString(h, strconv.FormatUint(pid, 10))
	token := fmt.Sprintf("%x", h.Sum(nil))

	return token, curtime
}

type JWT struct {
	jwt.StandardClaims
	UserID  uint64 `json:"user_id"`
	Channel string `json:"channel"`
	Isadult bool   `json:"isadult"`
}

// 生成JWT Token
func CreateJWTToken(uid uint64, timestamp int64, channel string, isadult bool) (accessToken string) {
	jwtmd := &JWT{
		UserID:  uid,
		Channel: channel,
		Isadult: isadult,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: timestamp,
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwtmd) // Changed to HS256
	accessToken, _ = token.SignedString(Jwkey)                // Ensure LoginSalt is used as a shared secret
	logger.Debugf(server.LogKey_LoginFlow, "CreateJWTToken success uid:%d,channel:%s,isadult:%t Token:%s", uid, channel, isadult, accessToken)
	return accessToken
}

// 校验JWT Token 校验成功返回jwtmd
func CheckJWTToken(token string) (jwtmd *JWT, err error) {
	jwtmd = new(JWT)
	result, err := jwt.ParseWithClaims(token, jwtmd, func(token *jwt.Token) (interface{}, error) {
		return Jwkey, nil
	})
	if result.Valid {
		logger.Debugf(server.LogKey_LoginFlow, "CheckJWTToken success Token:%s", token)
		return jwtmd, nil
	} else {
		logger.Warnf("CheckJWTToken fail Token:%s", token)
		return nil, err
	}
}
